package com.tuziki.zk.studio.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.tuziki.zk.studio.model.NodeData;
import com.tuziki.zk.studio.util.Constants;
import com.tuziki.zk.studio.view.MainView;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.GetChildrenBuilder;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.log4j.Logger;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/**
 * Created by Sannychan on 2015/3/23.
 */
public class ZKDataService {

    private static CuratorFramework client = null;

    static Logger logger = Logger.getLogger(ZKDataService.class.getName());

    public static void initTreeData(String zkAddr) {
        if (!checkZKServer(zkAddr)) {
            return;
        }
        connectZKServer(zkAddr);
        GetChildrenBuilder childrenBuilder = client.getChildren();
        try {
            List<String> childrens = childrenBuilder.forPath("/");
            MainView.getTreePane().setViewportView(initJtree(childrens));
            MainView.getTreePane().updateUI();
            logger.info("根节点初始化完成");
        } catch (Exception e) {
            logger.error("根节点加载失败", e);
        }
    }

    public static void main(String[] args) {
        initTreeData("127.0.0.1:2181");
    }

    private static void connectZKServer(String zkAddr) {
        if (client != null) {
            client.close();
        }
        logger.info("开始连接zk server:" + zkAddr);
        client = CuratorFrameworkFactory.builder().
                connectString(zkAddr).
                retryPolicy(new ExponentialBackoffRetry(1000, 3)).
                connectionTimeoutMs(5000).build();
        client.start();
        logger.info("连接zk server成功!");
    }

    private static boolean checkZKServer(String zkAddr) {
        try {
            String[] info = zkAddr.split(":");
            InetSocketAddress inetSocketAddress = new InetSocketAddress(info[0], Integer.parseInt(info[1]));
            Socket clientSocket = new Socket();
            clientSocket.connect(inetSocketAddress, 1000);
            clientSocket.close();
            return true;
        } catch (Exception e) {
            logger.error("zk server连接异常" + zkAddr, e);
            return false;
        }
    }


    private static JTree initJtree(List<String> childrens) {
        NodeData rootData = new NodeData("", Constants.ZK_ROOT_PATH);
        rootData.setExpand(true);
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootData);
        for (String child : childrens) {
            NodeData node = new NodeData(Constants.ZK_ROOT_PATH, child);
            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(node);
            root.add(treeNode);
        }
        final JTree tree = new JTree(root) {
            public Insets getInsets() {
                return new Insets(5, 5, 5, 5);
            }
        };

        final JPopupMenu jPopupMenu = initJtreeMenu();

        tree.addMouseListener(new MouseAdapter() {
            //jtree右键菜单
//            @Override
//            public void mouseReleased(MouseEvent e) {
//                if (e.isMetaDown()) {
//                    TreePath pathForLocation = tree.getPathForLocation(e.getX(), e.getY());
//                    Object clicked = pathForLocation.getLastPathComponent();
//                    if (DefaultMutableTreeNode.class.isInstance(clicked)) {
//                        tree.setSelectionPath(pathForLocation);
//                        jPopupMenu.show(tree, e.getX(), e.getY());
//                    }
//                }
//            }

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    if (e.getButton() != MouseEvent.BUTTON1) {
                        return;
                    }
                    TreePath pathForLocation = tree.getPathForLocation(e.getX(), e.getY());
                    Object clicked = pathForLocation.getLastPathComponent();
                    if (DefaultMutableTreeNode.class.isInstance(clicked)) {
                        DefaultMutableTreeNode clickNode = (DefaultMutableTreeNode) clicked;
                        NodeData clickNodeData = (NodeData) clickNode.getUserObject();
                        if (!clickNodeData.isExpand()) {
                            String parentPath = clickNodeData.getNodePath();
                            List<String> childrens = getChildNode(parentPath);
                            if (childrens.size() == 0) {
                                logger.warn(parentPath + "的没有子节点");
                                clickNodeData.setExpand(true);
                                return;
                            }
                            for (String child : childrens) {
                                NodeData nodeData = new NodeData(parentPath, child);
                                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(nodeData);
                                clickNode.add(newNode);
                            }
                            tree.updateUI();
                            tree.expandPath(new TreePath(clickNode.getPath()));
                            clickNodeData.setExpand(true);
                        }
//                        logger.info("双击:" + pathForLocation.getLastPathComponent());
                    }


                } else if (e.getClickCount() == 1) {
                    if (e.getButton() != MouseEvent.BUTTON1) {
                        return;
                    }
                    TreePath pathForLocation = tree.getPathForLocation(e.getX(), e.getY());
                    Object clicked = pathForLocation.getLastPathComponent();
                    if (DefaultMutableTreeNode.class.isInstance(clicked)) {
                        DefaultMutableTreeNode clickNode = (DefaultMutableTreeNode) clicked;
                        NodeData clickNodeData = (NodeData) clickNode.getUserObject();
                        showSelectNodeDatas(clickNodeData);
                    }
                }

            }


        });
        return tree;
    }

    private static void showSelectNodeDatas(NodeData clickNodeData) {
        try {
            Map<String, JTextPane> tabPanels = MainView.getTabsPanel();
            JTextPane dataPanel = tabPanels.get(Constants.DATA_TAB_NAMES[0]);
            JTextPane metaDataPanel = tabPanels.get(Constants.DATA_TAB_NAMES[1]);
            JTextPane aclPanel = tabPanels.get(Constants.DATA_TAB_NAMES[2]);
            byte[] content = client.getData().forPath(clickNodeData.getNodePath());
            dataPanel.setText(new String(content));
            List<ACL> acls = client.getACL().forPath(clickNodeData.getNodePath());
            aclPanel.setText(JSON.toJSONString(acls, SerializerFeature.PrettyFormat));
            Stat stat = client.checkExists().forPath(clickNodeData.getNodePath());
            metaDataPanel.setText(getNodeMetaData(stat));
        } catch (Exception e) {
            logger.info("节点" + clickNodeData.getNodePath() + "数据获取失败！");
        }
    }


    private static List<String> getChildNode(String parentPath) {
        GetChildrenBuilder childrenBuilder = client.getChildren();
        List<String> childrens = new ArrayList<String>();
        try {
            childrens = childrenBuilder.forPath(parentPath);
        } catch (Exception e) {
            logger.error("获取子节点失败", e);
        }
        return childrens;
    }


    private static String getNodeMetaData(Stat s) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Map<String, String> nodeMeta = new LinkedHashMap<String, String>();
        nodeMeta.put(Constants.A_VERSION, String.valueOf(s.getAversion()));
        nodeMeta.put(Constants.C_TIME, dateFormat.format(new Date(s.getCtime())));
        nodeMeta.put(Constants.C_VERSION, String.valueOf(s.getCversion()));
        nodeMeta.put(Constants.CZXID, String.valueOf(s.getCzxid()));
        nodeMeta.put(Constants.DATA_LENGTH, String.valueOf(s.getDataLength()));
        nodeMeta.put(Constants.EPHEMERAL_OWNER, String.valueOf(s.getEphemeralOwner()));
        nodeMeta.put(Constants.M_TIME, dateFormat.format(new Date(s.getMtime())));
        nodeMeta.put(Constants.MZXID, String.valueOf(s.getMzxid()));
        nodeMeta.put(Constants.NUM_CHILDREN, String.valueOf(s.getNumChildren()));
        nodeMeta.put(Constants.PZXID, String.valueOf(s.getPzxid()));
        nodeMeta.put(Constants.VERSION, String.valueOf(s.getVersion()));
        return JSON.toJSONString(nodeMeta, SerializerFeature.PrettyFormat);
    }


    private static JPopupMenu initJtreeMenu() {
        JPopupMenu popMenu = new JPopupMenu();
        JMenuItem createMenu = new JMenuItem("添加子节点");
        createMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

            }
        });
        JMenuItem deleteMenu = new JMenuItem("删除节点");
        deleteMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

            }
        });
        popMenu.add(createMenu);
        popMenu.add(deleteMenu);
        return popMenu;
    }
}
